package com.htdata.iiot.api.tsdb.pojo;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.apache.commons.lang.StringUtils;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;

/**
 * Data point for one sensor with metric and timestamp and tags
 *
 * @author sunmya
 *
 *
 * 通过com.fasterxml.jackson提供的序列化方法可以将数据序列化
 * DataPoint foo = new DataPoint();
 * int tenantid = 1;
 * int deviceid = 1;
 * long metricid = 1L;
 * DeviceNumber dn = new DeviceNumber(tenantid, deviceid, metricid);
 * foo.setDeviceNumber(dn);
 * foo.setTs(new Date().getTime());
 * Metric metric = new Metric();
 * metric.setName("sys.cpu");
 * metric.setValue(0.8);
 * foo.setMetric(metric);
 * foo.addTag("host", "127.0.0.1");
 * ObjectMapper mapper = new ObjectMapper();
 * String jsonInString = mapper.writeValueAsString(foo);
 *
 * 反序列化方法
 * ObjectMapper mapper = new ObjectMapper();
 * DataPoint fooBack = mapper.readValue(jsonInString, DataPoint.class);
 */
@JsonSerialize(using = DataPointSerializer.class)
@JsonDeserialize(using = DataPointDeserializer.class)
public class DataPoint implements Serializable {

	/**
	 *
	 */
	private static final long serialVersionUID = -3626511735222931717L;

	private DeviceNumber dn;

	private long ts;

	private Map<String, String> tags = new HashMap<String, String>();

	private Metric metric;

	public DeviceNumber getDeviceNumber() {
		return dn;
	}

	public void setDeviceNumber(DeviceNumber dn) {
		this.dn = dn;
		updateInternalTags();
	}

	public long getTs() {
		return ts;
	}

	public void setTs(long ts) {
		this.ts = ts;
	}

	public Map<String, String> getTags() {
		return tags;
	}

	public void addTag(String tagK, String TagV) {
		this.tags.put(tagK, TagV);
	}

	public void setTags(Map<String, String> tags) {
		this.tags = tags;
	}

	public Metric getMetric() {
		return metric;
	}

	public void setMetric(Metric metric) {
		this.metric = metric;
	}

	/**
	 * check if data point is valid
	 *
	 * @return true or false
	 */
	public boolean valid() {
		return ts > 0L && StringUtils.isNotEmpty(this.metric.getName());
	}

	/**
	 * add internal tags for datapoint with thingid and ...
	 */
	private void updateInternalTags() {
		if (this.dn != null) {
			this.addTag("deviceid", DataPoint.bytesToInt(this.dn.getDeviceId()) + "");
			this.addTag("metricid", DataPoint.bytesToLong(this.dn.getMetricId()) + "");
			this.addTag("tenantid", DataPoint.bytesToInt(this.dn.getTenantId()) + "");
		}

	}

	public static int bytesToInt(byte[] b)
	{
		ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
		buffer.put(b);
		buffer.flip();
		return buffer.getInt();
	}

	public static byte[] intToBytes(int x)
	{
		ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
		buffer.putInt(x);
		return buffer.array();
	}

	public static byte[] longToBytes(long x) {
		ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
		buffer.putLong(x);
		return buffer.array();
	}

	public static long bytesToLong(byte[] bytes) {
		ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
		buffer.put(bytes);
		buffer.flip();//need flip
		return buffer.getLong();
	}

	@Override
	public String toString() {
		return "DataPoint [dn=" + dn + ", ts=" + ts + ", tags=" + tags + ", metric=" + metric + "]";
	}
	public DataPoint(){

	}
}
